<template>
  <div>
    <el-table
      :border="border"
      :stripe="stripe"
      :data="_data"
      :max-height="maxHeight"
      :cell-style="cellStyle"
      :header-cell-style="headerCellStyle"
      :span-method="spanMethod"
      row-key="__id__"
      :default-expand-all="defaultExpandAll"
      :expand-row-keys="expandRowKeys"
    >
      <template #empty>
        <slot name="empty"></slot>
      </template>
      <!-- 序号列 -->
      <el-table-column
        v-if="index"
        label="序号"
        type="index"
        width="80px"
        align="center"
      ></el-table-column>
      <!-- 其他列 -->
      <el-table-column
        v-for="(col, index) in columns"
        :key="index"
        :label="col.label"
        :prop="col.prop"
        :fixed="col.fixed || null"
        :width="col.width || null"
        :min-width="col.minWidth || null"
        :align="col.align || 'center'"
        :filters="col.filters"
        :filter-method="col.filterMethod"
        :filter-placement="col.filterPlacement"
      >
        <template v-if="col.labelSlot" #header="scope">
          <!-- 插槽 label -->
          <slot :name="col.labelSlot" v-bind="scope"></slot>
        </template>
        <template #default="scope">
          <!-- 插槽 value -->
          <slot v-if="col.valueSlot" :name="col.valueSlot" v-bind="scope"></slot>
          <template v-else>
            {{ cellFormatter(scope.row, col, emptyCellText) }}
          </template>
        </template>
      </el-table-column>
    </el-table>

    <el-pagination
      v-if="pageable"
      class="table-base-pagination"
      :layout="pageLayout"
      :total="total"
      :pageSizes="[10, 20]"
      :hideOnSinglePage="hideOnSinglePage"
      v-model:current-page="currentPage"
      v-model:pageSize="pageSize"
      @current-change="changePage"
      @size-change="changeSize"
    ></el-pagination>
  </div>
</template>

<script setup name="TableBase">
import { toRefs, computed, inject, ref, watch } from 'vue'
import { thStyle, tdStyle, childRowBgColor } from './style'
import { cellFormatter } from './util'
/**
 * columns
 *     * 参数列举：{ label, prop, width, minWidth, formatter, align, isTh, labelSlot, valueSlot }
 *     * formatter 接收参数为(row, column, cellValue)
 *     * isTh 表示此列为标题
 */
const props = defineProps({
  columns: Array,
  data: Array,
  index: Boolean,
  border: {
    type: Boolean,
    default: true,
  },
  stripe: {
    type: Boolean,
    default: false,
  },
  maxHeight: [Number, String],
  spanMethod: Function,
  defaultExpandAll: {
    type: Boolean,
    default: false,
  },
  expandRowKeys: Array,
  filters: Array,
  filterPlacement: String,
  filterMethod: Function,
  pageable: Boolean,
  pageSize: {
    type: Number,
    default: 10,
  },
  pageLayout: {
    type: String,
    default: 'total, prev, pager, next, jumper',
  },
  hideOnSinglePage: {
    type: Boolean,
    default: true,
  },
})

const emptyCellText = inject('emptyCellText')

const { columns } = toRefs(props)

// 原始数据
let originData = []
// el-table使用的数据
const _data = ref([])
// 当前页码
const currentPage = ref(1)
// 每页行数
const pageSize = ref(props.pageSize)
// 总行数
const total = ref(0)

watch(
  () => props.data,
  (v) => {
    if (v && v.length > 0) {
      originData = addDataId(v)
      total.value = originData.length
      // 有分页时使用分页后的数据
      props.pageable ? changePage((currentPage.value = 1)) : (_data.value = originData)
    } else {
      originData = []
      total.value = 0
      _data.value = []
    }
  },
  { immediate: true }
)

// 分页变化
function changePage(num) {
  const start = pageSize.value * (num - 1)
  _data.value = originData.slice(start, start + pageSize.value)
}

// pageSize改变
function changeSize() {
  changePage(1)
}

// 为行和子行增加唯一id，使其支持树形数据
function addDataId(data) {
  let id = 0
  data.forEach((row) => {
    row.__id__ = id++
    if (row?.children?.length > 0) {
      row.children.forEach((childRow) => {
        childRow.__id__ = id++
        childRow.__isChildRow__ = true
      })
    }
  })
  return data
}

// 附带isTh的属性列表
const thPropArr = computed(() => {
  const arr = []
  columns?.value?.forEach((item) => {
    if (item.isTh) arr.push(item.prop)
  })
  return arr
})

function headerCellStyle() {
  return thStyle
}

function cellStyle({ row, column, rowIndex, columnIndex }) {
  if (thPropArr.value.indexOf(column.property) >= 0) {
    return thStyle
  } else if (row.__isChildRow__) {
    return Object.assign({}, tdStyle, { backgroundColor: childRowBgColor })
  } else {
    return tdStyle
  }
}
</script>

<style lang="stylus" scoped>
.table-base-pagination
  justify-content end
  margin-top 20px
</style>
